package com.yqh.wechat.controller;

import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.yqh.wechat.common.AppResponse;
import com.yqh.wechat.util.HttpUtil;
import com.yqh.wechat.util.WechatUtil;
import com.yqh.wechat.util.XMLUtil;

/**
 * 扫码支付
 * @author Yang.Qinghui
 * 接口文档：https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
 */
@RestController
@RequestMapping("/pay")
public class WechatPayController {

	private static final String APPID = "";
	private static final String MID = "";
	private static final String APP_KEY = "";
	private static final String PAY_ORCODE = "https://api.mch.weixin.qq.com/pay/unifiedorder";
	
	private static final String BODY = "支付测试";
	private static final String NOTIFY_URL = "http://*************/pay/notify";	// 回调链接
	private static final String TRADE_TYPE = "NATIVE";
	
	private static final int BLACK = 0xff000000;  
	private static final int WHITE = 0xFFFFFFFF;  

	
	
	/**
	 * 获取二维码
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/orCode")
	public AppResponse getORcode(HttpServletRequest request,HttpServletResponse response) throws Exception {

		AppResponse resp = new AppResponse();

		Integer total_fee = 100;

		SortedMap<Object, Object> params = new TreeMap<>();
		params.put("appid", APPID);
		params.put("mch_id", MID);
		params.put("nonce_str", WechatUtil.getRandomStringByLength(10));
		params.put("body", BODY);
		params.put("out_trade_no", WechatUtil.getCurrTime());
		params.put("total_fee", total_fee);
		params.put("spbill_create_ip", WechatUtil.localIp());
		params.put("notify_url", NOTIFY_URL);
		params.put("trade_type", TRADE_TYPE);
		// 生成签名
		params.put("sign", WechatUtil.createSign("UTF-8", params, APP_KEY));
		// 生成xml
		String xml = WechatUtil.getRequestXml(params);
		System.out.println("[ WechatPayController getORcode ] doPost xml:" + xml);

		String result = HttpUtil.postData(PAY_ORCODE, xml);
		System.out.println("[ WechatPayController getORcode ] doPost result:" + result);
		
		Map<String, String> map = XMLUtil.doXMLParse(xml);

		String prepay_id = map.get("prepay_id");
		System.out.println("[ WechatPayController getORcode ] result prepay_id:" + prepay_id);

		String code_url = map.get("code_url");
		System.out.println("[ WechatPayController getORcode ] result code_url:" + code_url);

		// 生成二维码
		encodeQrcode(code_url, response);
		
		// 支付记录入库，默认没有支付状态 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
		
		
		
		
		resp.setData(result);
		return resp;
		
	}
	
	
	/**
	 * 扫码回掉链接
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping("/notify")
	public void payNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
		
		// 读取参数
		StringBuffer sb = new StringBuffer();    
		InputStream inputStream = null ; 
		BufferedReader in = null ;
        try {
			inputStream = request.getInputStream();    
			String line ;    
			in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));    
			while ((line = in.readLine()) != null){    
			    sb.append(line);    
			}    
		} finally {
			if(in != null)	in.close();    
			if(inputStream != null) inputStream.close();
		}
        
        //解析xml成map    
        Map<String, String> map = XMLUtil.doXMLParse(sb.toString());
        
        //过滤空 设置 TreeMap  
        SortedMap<Object,Object> packageParams = new TreeMap<>();        
        Iterator<String> it = map.keySet().iterator();  
        while (it.hasNext()) {  
            String parameter = it.next();
            String parameterValue = map.get(parameter);
            String v = "";  
            if(null != parameterValue) {
                v = parameterValue.trim();  
            }  
            packageParams.put(parameter, v);  
        }
        
        System.out.println("[ WechatPayController payNotify ] packageParams:" + JSONObject.toJSONString(packageParams));
        
        if(WechatUtil.isTenpaySign("UTF-8", packageParams, APP_KEY)){
        	
        	String resXml = "";  
        	
        	String result_code = (String)packageParams.get("result_code");
            if("SUCCESS".equals(result_code)){ 
            	
            	System.out.println("[ WechatPayController payNotify ] isTenpaySign SUCCESS !");
            	
            	String appid = (String)packageParams.get("appid");
            	String mch_id = (String)packageParams.get("mch_id");
            	String nonce_str = (String)packageParams.get("nonce_str");
            	String body = (String)packageParams.get("body");
            	String out_trade_no = (String)packageParams.get("out_trade_no");
            	String total_fee = (String)packageParams.get("total_fee");
            	String spbill_create_ip = (String)packageParams.get("spbill_create_ip");
            	String trade_type = (String)packageParams.get("trade_type");
            	
            	System.out.println("appid:" + appid);
            	System.out.println("mch_id:" + mch_id);
            	System.out.println("nonce_str:" + nonce_str);
            	System.out.println("body:" + body);
            	System.out.println("out_trade_no:" + out_trade_no);
            	System.out.println("total_fee:" + total_fee);
            	System.out.println("spbill_create_ip:" + spbill_create_ip);
            	System.out.println("trade_type:" + trade_type);
            	
            	// 更新支付记录，成功 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
            	
            	
            	System.out.println("[ WechatPayController payNotify ] result_code SUCCESS !");
            	
            	//通知微信，异步确认成功
            	resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"    
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            	
            }else{
            	
            	// 更新只读记录，失败 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
            	String error_msg = "result_code:" + result_code + ";return_msg:" + packageParams.get("return_msg");
            	
            	
            	
            	System.out.println("[ WechatPayController payNotify ] result_code FAIL !");
            	
            	resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"    
                        + "<return_msg><![CDATA[error message]]></return_msg>" + "</xml> ";
            }
        	
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());    
            out.write(resXml.getBytes());    
            out.flush();    
            out.close();  
        	
        }else{
        	
        	// 理论不出现 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        	
        	
        	System.out.println("[ WechatPayController payNotify ] isTenpaySign FAIL !");
        }
        
	}
	
	

	/**
	 * 将路径生成二维码图片
	 * 	js:前端页面用jquery.qrcode.min.js解析
	 * @param content
	 * @param response
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void encodeQrcode(String content, HttpServletResponse response) {

		if (StringUtils.isBlank(content))
			return;
		MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
		Map hints = new HashMap();
		BitMatrix bitMatrix = null;
		try {
			bitMatrix = multiFormatWriter.encode(content,
					BarcodeFormat.QR_CODE, 250, 250, hints);
			BufferedImage image = toBufferedImage(bitMatrix);
			// 输出二维码图片流
			try {
				ImageIO.write(image, "png", response.getOutputStream());
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (WriterException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * 类型转换
	 * @param matrix
	 * @return
	 */
	public BufferedImage toBufferedImage(BitMatrix matrix) {
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, matrix.get(x, y) == true ? BLACK : WHITE);
			}
		}
		return image;
	}
	
	

}
